package com.AdvancedDemos.Stream流操作;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class Stream流中间方法 {
    public static void main(String[] args) {
        //Stream流中间方法
        //在Stream流中对数据进行操作的方法
        //方法执行完毕后返回的是处理完毕后数据的Stream流对象,于是可以链式编程

        /*
        注意:Stream流操作数据,数据流是单向的,不可逆的. 只能继续使用处理完后返回的新流对象继续处理 . 如果使用过流后,想从流之前的状态开始,需要使用原来的数组,集合,数据重新获取新的Stream
         */

        /**
         * Stream流让数据流动起来使用的是迭代器,在使用Stream流操作数据时不要使用容器自身的增删方法,会造成并发修改异常
         */

        ArrayList<String> list = new ArrayList<>(List.of("11", "31", "222", "32", "333", "4444", "55555", "222", "222", "222"));
        Stream<String> stream = list.stream();


//        //1.Stream<T> filter(Predicate<? super T> predicate) --- 数据过滤
//        Stream<String> afterFilterStream = stream.filter(new Predicate<String>() {//predicate v.断言,断定
//            @Override
//            public boolean test(String s) {//String s 依次代表流中每一个元素,如果返回结果为true,那么该条数据保留,如果结果为false,将该条数据从流中删除
//                return s.startsWith("3");
//            }
//        });
//        System.out.println(afterFilterStream);//java.util.stream.ReferencePipeline$2@b4c966a 直接打印流将输出地址
//
//        afterFilterStream.forEach(/*new Consumer<String>() {//输出流要用forEach(),使用后流关闭,后续将不能再对该流对象操作,需要重新从集合打开新的流
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        }*/
//                //简化为Lambda表达式
//                /*s -> System.out.println(s)*/
//                //简化为方法引用
//                System.out::println);
//        //java.util.stream.ReferencePipeline$2@b4c966a
//        //31
//        //32
//        //333


//        //2.Stream<T> sorted() --- 使用元素的自然排序
//        stream.sorted()/*此处因为集合中元素是String类型,所以将按照ASCII码值排序*/.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//                //11
//                //222
//                //222
//                //222
//                //222
//                //31
//                //32
//                //333
//                //4444
//                //55555
//            }
//        });


//        //3.Stream<T> sorted(Comparator<? super T> comparator) --- 使用比较器排序,按长度逆序
//        stream.sorted(new Comparator<String>() {
//            /**
//             * sorted自然排序默认是按照升序排序的
//             * public int compare(String o1, String o2)函数默认规则:
//             * o1–第一个要比较的对象。
//             * o2–第二个要比较的对象。
//             * 返回 负整数 代表 第一个参数 < 第二个参数
//             * 返回   零   代表 第一个参数 = 第二个参数
//             * 返回 正整数 代表 第一个参数 > 第二个参数
//             *
//             * 🔴简单记忆就是:
//             * 返回负整数 - 不变换顺序 - o1在前o2在后
//             * 返回正整数 - 交换顺序   - o2在前o1在后
//             *
//             * 也就是说想要升序排序,只需要
//             * 在o1<o2时 - 无需变换顺序 - 返回负整数
//             * 在o1=o2时 - 无需变换顺序 - 返回0
//             * 在o1>o2时 - 需要交换顺序 - 返回正整数
//             *
//             * 想要实现降序排序,只需要
//             * 在o1<o2时 - 需要交换顺序 - 返回正整数
//             * 在o1=o2时 - 无需变换顺序 - 返回0
//             * 在o1>o2时 - 无需变换顺序 - 返回负整数
//             */
//            @Override
//            public int compare(String o1, String o2) {
//                //第一种方式:if else 判断
//                if (o2.length() == o1.length()) {//无需交换
//                    return 0;
//                } else if (o2.length() < o1.length()) {//无需交换
//                    return -1;
//                } else {//o2.length() > o1.length() 需要交换
//                    return 1;
//                }
//
//                //第二种方式:使用Integer.compare()函数
////                return Integer.compare(o2.length(), o1.length());
//                /*x – the first int to compare;
//                y – the second int to compare;
//                return the value 0 if x == y;
//                a value less than 0 if x < y;
//                and a value greater than 0 if x > y*/
//
//                //第三种方式:直接return 整数1 - 整数2
////                return o2.length() - o1.length();
//            }
//        }).forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//                //55555
//                //4444
//                //222
//                //333
//                //222
//                //222
//                //222
//                //11
//                //31
//                //32
//            }
//        });


//        //4.Stream<T> limit(long maxSize) --- 保留指定个数数据,如果传入的  保留数据个数 > 元素个数  ,将以当前元素个数为准
//        /*Stream<String> limit = stream.limit(100);//超出了实际元素个数
//        limit.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//                //11
//                //31
//                //222
//                //32
//                //333
//                //4444
//                //55555
//                //222
//                //222
//                //222
//            }
//        });*/
//        Stream<String> limit1 = stream.limit(5);
//        limit1.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//                //11
//                //31
//                //222
//                //32
//                //333
//            }
//        });


//        //5.Stream<T> skip(long n) --- 跳过指定个数的数据,如果跳过元素个数 > 流中元素个数, 相当于一个数据不取
//        Stream<String> skip = stream.skip(3);
//        skip.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//                //32
//                //333
//                //4444
//                //55555
//                //222
//                //222
//                //222
//            }
//        });


//    //6.Stream<T> distinct() --- 去除流中重复数据,依靠的是元素的hashCode()和equals(),并且去除流中重复操作不影响集合中原始数据
//        //distinct a.不同的,清晰的,明显的
//        Stream<String> stream1 = list.stream();
//        stream1.distinct().forEach(s -> System.out.println(s));
//        //11
//        //31
//        //222
//        //32
//        //333
//        //4444
//        //55555


//        //7.static <T> Stream<T> concat(Stream<? extends T> a,Stream<? extends T> b) --- 将两个Stream流中的数据合并为一个Stream流
//        //concatenate v.连接
//        ArrayList<String> list1 = new ArrayList<>(List.of("蓝球", "背带裤", "中分头"));
//        ArrayList<String> list2 = new ArrayList<>(List.of("唱", "跳", "Rap"));
//        Stream<String> stream1 = list1.stream();
//        Stream<String> stream2 = list2.stream();
//        Stream<String> concat = Stream.concat(stream1, stream2);
//        concat.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//                //蓝球
//                //背带裤
//                //中分头
//                //唱
//                //跳
//                //Rap
//            }
//        });

//        //8. <R> Stream <R> map(Function <? super T,? extends R> mapper)---改变元素的映射关系(类型转换)
//        ArrayList<String> list1 = new ArrayList<>(List.of("蓝球", "背带裤", "中分头"));
//        //将流中每个String数据作为Student构造函数的参数,转化为Student对象
//        //原来的做法是
//        /*
//        //1.定义存储Student对象的集合
//        ArrayList<Student> students = new ArrayList<>();
//        //2.获取String参数
//        for (String s : list1) {
//            Student stu = new Student(s);
//            students.add(stu);
//        }
//        for (Student student : students) {
//            System.out.println(student);
//        }
//        */
//        //使用流操作
//        Stream<String> stream1 = list1.stream();
//        Stream<Student> studentStream = stream1.map(new Function<String, Student>() {//表示要将String泛型流转换成Student泛型流
//            @Override
//            public Student apply(String s) {
//                return new Student(s);//手动将String包装成Student
//            }
//        });
//        studentStream.forEach(new Consumer<Student>() {
//            @Override
//            public void accept(Student student) {
//                System.out.println(student);
//                //Student{skill='蓝球'}
//                //Student{skill='背带裤'}
//                //Student{skill='中分头'}
//            }
//        });


    }
}

class Student {
    private String skill;

    public Student(String skill) {
        this.skill = skill;
    }

    @Override
    public String toString() {
        return "Student{" + "skill='" + skill + '\'' + '}';
    }
}